#include <iostream>
const double * f1(const double ar[], int n);
const double * f2(const double [], int);
const double * f3(const double [], int);
/*
与数据相似，函数也有自己的地址
例子：设计一个estimate的函数，估算编写指定行数的代码所需要的时间，并且希望不同的程序员都可以使用该函数
但是，要求由每个程序员自己提供算法函数计算时间，所以需要将算法函数的地址传递给estimate()
*/
/*
过程：
1. 获取一个函数的地址：直接使用函数名即可代表地址，不能带括号
2. 申明一个函数指针
3. 使用函数指针调用函数
*/

/*
prototype函数原型: double func(int a)
那么正确的函数指针申明：
double (*pf)(int);
表明：pf指针指向的函数返回double，且接受int参数
注意：pf是函数指针，(*pf)才是函数，必须使用括号将*pf括起来，整体才表示函数
最后：需要把函数的地址赋值给函数指针
pf = func
*/
void estimate(int lines, double (*pf)(int)){
    double b = (*pf)(lines);
    std::cout << "b = " << b << std::endl;
}

double pam(int a){
    double b = a;
    return b;
}

double besty(int a){
    double b = a * 0.8;
    return b;
}

/*
const double * f1(const double ar[], int n);
const double * f2(const double [], int);
const double * f3(const double *, int);
函数原型prototype 就是函数申明，参数可以只写数据类型，不用写标识符
*/

const double * f1(const double ar[], int n){

    //C++传递数组作为参数时传递的并不是数组的本身，而是数组的第一个元素的地址，所以还必须传递数组的长度作为参数
    /*
    std::cout << "size2 = " << sizeof(ar) / sizeof(ar[0]) << std::endl;
    for(int i = 0, len = sizeof(ar) / sizeof(ar[0]); i++; i < len){
        std::cout << "i = " << ar[i] << std::endl;
    }*/
    std::cout << "n = " << n << std::endl;
    for(int i = 0; i < n; i++){
        //std::cout << "i = " << i << std::endl;
        std::cout << "i = " << ar[i] << std::endl;
    }
    double r = 1.0;
    return &r;
}

const double * f2(const double ar[], int n){
    double r = 2.0;
    return &r;
}

const double * f3(const double ar[], int n){
    double r = 3.0;
    return &r;
}



int main(){
    estimate(50, pam);
    estimate(50, besty);

    //可以直接把函数原型（不带标志符的原型）中的函数名字替换成函数指针
    const double * (*pf)(const double [], int) = f1;
    //申明函数指针的同时进行初始化
    //甚至可以直接使用auto自动判断
    auto p2 = f1;   //使用-std=c++11编译
    double ar[5] = {1,2,3,4,5};
    std::cout << "size1 = " << sizeof(ar) / sizeof(ar[0]) << std::endl;
    std::cout << (*pf)(ar, 5) << std::endl;  //返回的是double数字的地址
    std::cout << *(*pf)(ar, 5) << std::endl;
    std::cout << "===" << std::endl;
    std::cout << p2(ar, 5) << std::endl;  //返回的是double数字的地址
    std::cout << *p2(ar, 5) << std::endl;

    //定义一个包含3个函数指针的数组
    const double * (*pa[3]) (const double [], int) = {f1, f2, f3};
    //这里不能使用auto，自动推断只能推断单值初始化，不能推断列表的初始化

    const double  r1 = *pa[0](ar, 5);
    const double  r2 = *pa[1](ar, 5);
    const double  r3 = *pa[2](ar, 5);
    std::cout << "r1 = " << r1 << ", r2 = " << r2 << ", r3 = " << r3 << std::endl;

    return 0;
}


// 2021-09-05 c++primer 264